home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Snippets / Simple C Sound / Sound.c < prev   
Text File  |  1996-06-25  |  9KB  |  331 lines

  1. /*
  2.         Sound.c
  3.         
  4.         Simple plug-in source to play sounds (2-channels) asynchronously. OK, so it won't do for a highly polished game
  5.         which needs four-channel double-buffering, but it suffices for most stuff.
  6.  
  7.         By Ross Younger, ©1996. You are free to use any or all of this source code in your own projects. Just don't ask me 
  8.         to support it. 
  9.  
  10.         Caveat: Of course, async sounds don't by default report back when they are finished. You might want to modify the 
  11.         callback procs if you feel so inclined. Good luck!
  12.  
  13.         
  14.         ** DO NOT ADD THIS FILE DIRECTLY TO YOUR PROJECT ** 
  15.         Copy it, and add the copy, because you need to alter the constants. 
  16. */
  17.  
  18. #include <MixedMode.h>
  19. #include <Sound.h>
  20.  
  21. #define kNumberSounds        3            // number of sounds to load
  22. #define kFirstSoundID        1000        // ID of first sound
  23.  
  24. /*
  25.     Change the constants to match your resources. The sounds are assumed to be sequential, starting with kFirstSoundID.
  26.     
  27.     Call InitSound() during your init routine. This will load in all the sounds, taking up space in your heap zone.
  28.     Call KillSound() during your cleanup. 
  29.     
  30.     To play a sound, use PlayASound(soundNumber, priority);
  31.         where soundNumber is the number within the file (starting at 0); eg. with sounds ID 100 thru 105, 
  32.         soundNumber 4 would give 'snd ' ID 103.
  33.         
  34.         PlayASound handles priorities like this:
  35.         if [ (channel1clear) or (newpriority >= sound1currentpriority) ], play sound on channel 1
  36.         else if [ (channel2clear) or (newpriority >= sound1currentpriority) ], play sound on channel 2
  37.         else ignore the sound  request.
  38.         
  39.         Or, for those of us who speak English: a sound of a higher (or equal) priority will override one that is still playing. 
  40.         The PlayASound routine tries to find a free channel, or one whose priority is greater than or equal to the one already 
  41.         playing there.
  42.     
  43. *    Check out the InitSound; it has error traps that give off weird return values.    *
  44.  
  45. */
  46.  
  47. // Constants
  48. #define kSoundDone                913
  49. #define kSoundDone2                749
  50.  
  51. // Prototypes
  52. short InitSound (void);
  53. void KillSound (void);
  54. void PlayASound (short soundID, short priority);
  55.  
  56. void PlaySound1 (short, short);
  57. void PlaySound2 (short, short);
  58. pascal void ExternalCallBack (SndChannelPtr, SndCommand);
  59. pascal void ExternalCallBack2 (SndChannelPtr, SndCommand);
  60. void LoadAllSounds (void);
  61. OSErr LoadBufferSounds (void);
  62. OSErr DumpBufferSounds (void);
  63. OSErr OpenSoundChannel (void);
  64. OSErr CloseSoundChannel (void);
  65.  
  66. // Globals for this source file
  67. SndCallBackUPP        externalCallBackUPP, externalCallBackUPP2;
  68. SndChannelPtr        externalChannel, externalChannel2;
  69. Ptr                    theSoundData[kNumberSounds];
  70. short                externalPriority, externalPriority2;
  71. Boolean                channelOpen, soundOn;
  72.  
  73. /**********************************************************************************/
  74. /*
  75.     You *can* use PlaySound1 and PlaySound2 directly, but I wouldn't recommend it.
  76. */
  77. void PlaySound1 (short soundID, short priority)
  78. {
  79.     SndCommand    theCommand;
  80.     OSErr        theErr;
  81.     
  82.     theCommand.cmd = flushCmd;
  83.     theCommand.param1 = 0;
  84.     theCommand.param2 = 0L;
  85.     theErr = SndDoImmediate(externalChannel, &theCommand);
  86.     
  87.     theCommand.cmd = quietCmd;
  88.     theCommand.param1 = 0;
  89.     theCommand.param2 = 0L;
  90.     theErr = SndDoImmediate(externalChannel, &theCommand);
  91.     
  92.     externalPriority = priority;
  93.     
  94.     theCommand.cmd = bufferCmd;
  95.     theCommand.param1 = 0;
  96.     theCommand.param2 = (long)(theSoundData[soundID]);
  97.     theErr = SndDoImmediate(externalChannel, &theCommand);
  98.     
  99.     theCommand.cmd = callBackCmd;
  100.     theCommand.param1 = kSoundDone;
  101.     theCommand.param2 = SetCurrentA5();
  102.     theErr = SndDoCommand(externalChannel, &theCommand, true);
  103. }
  104. /**********************************************************************************/
  105. void PlaySound2 (short soundID, short priority)
  106. {
  107.     SndCommand    theCommand;
  108.     OSErr        theErr;
  109.     
  110.     theCommand.cmd = flushCmd;
  111.     theCommand.param1 = 0;
  112.     theCommand.param2 = 0L;
  113.     theErr = SndDoImmediate(externalChannel2, &theCommand);
  114.     
  115.     theCommand.cmd = quietCmd;
  116.     theCommand.param1 = 0;
  117.     theCommand.param2 = 0L;
  118.     theErr = SndDoImmediate(externalChannel2, &theCommand);
  119.     
  120.     externalPriority2 = priority;
  121.     
  122.     theCommand.cmd = bufferCmd;
  123.     theCommand.param1 = 0;
  124.     theCommand.param2 = (long)(theSoundData[soundID]);
  125.     theErr = SndDoImmediate(externalChannel2, &theCommand);
  126.     
  127.     theCommand.cmd = callBackCmd;
  128.     theCommand.param1 = kSoundDone2;
  129.     theCommand.param2 = SetCurrentA5();
  130.     theErr = SndDoCommand(externalChannel2, &theCommand, true);
  131. }
  132. /**********************************************************************************/
  133. void PlayASound (short soundID, short priority)
  134. // Remember! Pass as soundID the sound-number-in-file, NOT the ID!
  135. {
  136.     if ((soundID >= 0) && (soundID < kNumberSounds)) // Ignore invalid IDs
  137.     {
  138.         if (soundOn)
  139.         {
  140.             if (externalPriority < externalPriority2)
  141.             {
  142.                 if (priority >= externalPriority)
  143.                     PlaySound1(soundID, priority);
  144.             }
  145.             else
  146.             {
  147.                 if (priority >= externalPriority2)
  148.                     PlaySound2(soundID, priority);
  149.             }
  150.         }
  151.     }
  152. }
  153. /**********************************************************************************/
  154. // Don't worry about this macro! Just accept it!
  155.  
  156. RoutineDescriptor ExternalCallBackRD = 
  157.         BUILD_ROUTINE_DESCRIPTOR(uppFilePlayCompletionProcInfo, ExternalCallBack);
  158.  
  159. pascal void ExternalCallBack (SndChannelPtr theChannel, SndCommand theCommand)
  160. {
  161.     long        thisA5, wasA5;
  162.     
  163.     if (theCommand.param1 == kSoundDone)
  164.     {
  165.         wasA5 = theCommand.param2;
  166.         thisA5 = SetA5(wasA5);
  167.         
  168.         externalPriority = 0;
  169.         
  170.         thisA5 = SetA5(thisA5);
  171.     }
  172. }
  173. /**********************************************************************************/
  174. RoutineDescriptor ExternalCallBackRD2 = 
  175.         BUILD_ROUTINE_DESCRIPTOR(uppFilePlayCompletionProcInfo, ExternalCallBack2);
  176.  
  177. pascal void ExternalCallBack2 (SndChannelPtr theChannel, SndCommand theCommand)
  178. {
  179.     long        thisA5, wasA5;
  180.     
  181.     if (theCommand.param1 == kSoundDone2)
  182.     {
  183.         wasA5 = theCommand.param2;
  184.         thisA5 = SetA5(wasA5);
  185.         
  186.         externalPriority2 = 0;
  187.         
  188.         thisA5 = SetA5(thisA5);
  189.     }
  190. }
  191. /**********************************************************************************/
  192. OSErr LoadBufferSounds (void)
  193. {
  194.     Handle        theSound;
  195.     long        soundDataSize;
  196.     OSErr        theErr;
  197.     short        i;
  198.     
  199.     theErr = noErr;
  200.     
  201.     for (i = 0; i < kNumberSounds; i++)
  202.     {
  203.         theSound = GetResource('snd ', i + kFirstSoundID);
  204.         if (theSound == 0L)
  205.             return (ResError());
  206.         
  207.         HLock(theSound);
  208.         soundDataSize = GetHandleSize(theSound) - 20L;
  209.         HUnlock(theSound);
  210.         
  211.         theSoundData[i] = NewPtr(soundDataSize);
  212.         if (theSoundData[i] == 0L)
  213.             return (ResError());
  214.         HLock(theSound);
  215.         BlockMove((Ptr)(*theSound + 20L), theSoundData[i], soundDataSize);
  216.         HUnlock(theSound);
  217.         ReleaseResource(theSound);
  218.     }
  219.     
  220.     return (theErr);
  221. }
  222. /**********************************************************************************/
  223. OSErr DumpBufferSounds (void)
  224. {
  225.     OSErr        theErr;
  226.     short        i;
  227.     
  228.     theErr = noErr;
  229.     
  230.     for (i = 0; i < kNumberSounds; i++)
  231.     {
  232.         if (theSoundData[i] != 0L)
  233.             DisposPtr(theSoundData[i]);
  234.         theSoundData[i] = 0L;
  235.     }
  236.     
  237.     return (theErr);
  238. }
  239. /**********************************************************************************/
  240. OSErr OpenSoundChannel (void)
  241. {
  242.     OSErr        theErr;
  243.     
  244.     #if USESROUTINEDESCRIPTORS
  245.         externalCallBackUPP = &ExternalCallBackRD;
  246.         externalCallBackUPP2 = &ExternalCallBackRD2;
  247.     #else
  248.         externalCallBackUPP = (SndCallBackUPP) &ExternalCallBack;
  249.         externalCallBackUPP2 = (SndCallBackUPP) &ExternalCallBack2;
  250.     #endif
  251.     
  252.     theErr = noErr;
  253.     
  254.     if (channelOpen)
  255.         return (theErr);
  256.     
  257.     externalChannel = 0L;
  258.     theErr = SndNewChannel(&externalChannel, 
  259.             sampledSynth, initNoInterp + initMono, 
  260.             (SndCallBackUPP)externalCallBackUPP);
  261.     if (theErr == noErr)
  262.         channelOpen = true;
  263.     
  264.     externalChannel2 = 0L;
  265.     theErr = SndNewChannel(&externalChannel2, 
  266.             sampledSynth, initNoInterp + initMono, 
  267.             (SndCallBackUPP)externalCallBackUPP2);
  268.     if (theErr == noErr)
  269.         channelOpen = true;
  270.     
  271.     return (theErr);
  272. }
  273. /**********************************************************************************/
  274. OSErr CloseSoundChannel (void)
  275.  
  276. {
  277.     OSErr        theErr;
  278.     
  279.     theErr = noErr;
  280.     
  281.     if (!channelOpen)
  282.         return (theErr);
  283.     
  284.     if (externalChannel != 0L)
  285.         theErr = SndDisposeChannel(externalChannel, true);
  286.     externalChannel = 0L;
  287.     
  288.     if (externalChannel2 != 0L)
  289.         theErr = SndDisposeChannel(externalChannel2, true);
  290.     externalChannel2 = 0L;
  291.     
  292.     if (theErr == noErr)
  293.         channelOpen = false;
  294.     
  295.     return (theErr);
  296. }
  297. /**********************************************************************************/
  298. short InitSound (void)
  299. /*
  300.     This function loads the sounds and opens the channels. Return value is 0 for success, -1 for couldn't load the sounds, 
  301.     and -2 for couldn't open the channels.
  302. */
  303. {
  304.     OSErr        theErr;
  305.     
  306.     soundOn = true;
  307.     
  308.     externalChannel = 0L;
  309.     externalChannel2 = 0L;
  310.     externalPriority = 0;
  311.     externalPriority2 = 0;
  312.     
  313.     theErr = LoadBufferSounds();
  314.     if (theErr != noErr) // Failed to load the sounds (missing resource?). You might want to change how this is handled. 
  315.         return (-1);
  316.     
  317.     theErr = OpenSoundChannel();
  318.     if (theErr != noErr) // Couldn't open the sound channels (already in use?). Again, you may want to change how this is handled.
  319.         return (-2);
  320.     return (0); // 0 for success!
  321. }
  322. /**********************************************************************************/
  323. void KillSound (void)
  324. {
  325.     OSErr        theErr;
  326.     
  327.     theErr = DumpBufferSounds();
  328.     theErr = CloseSoundChannel();
  329. }    // Errors are ignored as we're closing down anyway.
  330. /**********************************************************************************/
  331. // The end.